package org.quickstart.netty.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * <p>描述: [功能描述] </p >
 *
 * @author yangzl
 * @version v1.0
 * @date 2020/9/16 11:25
 */
public class Server {

  private Selector selector;
  private ByteBuffer readBuffer = ByteBuffer.allocate(1024);//调整缓存的大小可以看到打印输出的变化
  private ByteBuffer sendBuffer = ByteBuffer.allocate(1024);//调整缓存的大小可以看到打印输出的变化

  String str;


  public static void main(String[] args) throws IOException {
    System.out.println("server started...");
    new Server().start();
  }


  public void start() throws IOException {
    // 打开服务器套接字通道
    ServerSocketChannel ssc = ServerSocketChannel.open();
    // 服务器配置为非阻塞
    ssc.configureBlocking(false);
    // 进行服务的绑定
    ssc.bind(new InetSocketAddress("localhost", 8001));

    // 通过open()方法找到Selector
    selector = Selector.open();
    // 注册到selector，等待连接
    ssc.register(selector, SelectionKey.OP_ACCEPT);

    while (!Thread.currentThread().isInterrupted()) {
      selector.select();
      Set<SelectionKey> keys = selector.selectedKeys();
      Iterator<SelectionKey> keyIterator = keys.iterator();
      while (keyIterator.hasNext()) {
        SelectionKey key = keyIterator.next();
        if (!key.isValid()) {
          continue;
        }
        if (key.isAcceptable()) {
          accept(key);
        } else if (key.isReadable()) {
          read(key);
        } else if (key.isWritable()) {
          write(key);
        }
        keyIterator.remove(); //该事件已经处理，可以丢弃
      }
    }
  }

  private void write(SelectionKey key) throws IOException, ClosedChannelException {
    SocketChannel channel = (SocketChannel) key.channel();
    System.out.println("Server write:" + str);

    sendBuffer.clear();
    sendBuffer.put(str.getBytes());
    sendBuffer.flip();
    channel.write(sendBuffer);
    channel.register(selector, SelectionKey.OP_READ);
  }

  private void read(SelectionKey key) throws IOException {
    SocketChannel socketChannel = (SocketChannel) key.channel();

    // Clear out our read buffer so it's ready for new data
    this.readBuffer.clear();
    //        readBuffer.flip();
    // Attempt to read off the channel
    int numRead;
    try {
      numRead = socketChannel.read(this.readBuffer);
    } catch (IOException e) {
      // The remote forcibly closed the connection, cancel
      // the selection key and close the channel.
      key.cancel();
      socketChannel.close();

      return;
    }

    str = new String(readBuffer.array(), 0, numRead);
    System.out.println("Server receive message: " + str);
    socketChannel.register(selector, SelectionKey.OP_WRITE);
  }

  private void accept(SelectionKey key) throws IOException {
    ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
    SocketChannel clientChannel = ssc.accept();
    clientChannel.configureBlocking(false);
    clientChannel.register(selector, SelectionKey.OP_READ);
    System.out.println("a new client connected " + clientChannel.getRemoteAddress());
  }

}